#pragma once
/*--------------------------------------------------------------------------------
 * Adaptive Intelligence - Foundation Framework Class Library
 * Version 2.00
 * 
 * Impersonation Session Class
 *      Provides a mechanismn for executing code under alternative credentials.
 *------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------
 * System Imports
 *------------------------------------------------------------------------------*/
#include "stdafx.h"

using namespace System;
using namespace System::Security;
using namespace System::Security::Permissions;
using namespace System::Security::Principal;
using namespace System::Runtime::InteropServices;
using namespace System::ComponentModel;
using namespace Adaptive::Foundation;

namespace Adaptive
{
	namespace Win32
	{
		public ref class ImpersonationSession : public DisposableObjectBase
		{
		public:
			/*--------------------------------------------------------------------------------
			 * Public Event Definitions
			 *------------------------------------------------------------------------------*/
			#pragma region Public Event Definitions
			/// <summary>
			/// Occurs when the user login succeeds.
			/// </summary>
			virtual event EventHandler^ UserLoginSuccess;
			/// <summary>
			/// Occurs when the user login fails.
			/// </summary>
			virtual event EventHandler^ UserLoginFailure;
			/// <summary>
			/// Occurs when the token duplication process fails.
			/// </summary>
			virtual event EventHandler^ TokenDuplicationFailure;
			/// <summary>
			/// Occurs when the impersonation context cannot be created.
			/// </summary>
			virtual event EventHandler^ ImpersonationContextFailure;
			/// <summary>
			/// Occurs when the impersonation is successful.
			/// </summary>
			virtual event EventHandler^ ImpersionationSuccess;
			/// <summary>
			/// Occurs when the impersonation session is ended.
			/// </summary>
			virtual event EventHandler^ ImpersionationEnded;
			#pragma endregion

			/*--------------------------------------------------------------------------------
			 * Constructor / Dispose / Destructor Methods
			 *------------------------------------------------------------------------------*/
			#pragma region Constructor / Dispose / Destructor Methods
			/// <summary>
			/// Initializes a new instance of the class.
			/// </summary>
			/// <remarks>
			/// This is the default constructor.
			/// </remarks>
			ImpersonationSession();
			
			!ImpersonationSession();
			#pragma endregion

			/*--------------------------------------------------------------------------------
			 * Public Properties
			 *------------------------------------------------------------------------------*/
			#pragma region Public Properties
			/// <summary>
			/// Gets the login token.
			/// </summary>
			/// <value>
			/// An <see cref="IntPtr"/> containing the user login token, or IntPtr.Zero if not assigned.
			/// </value>
			property IntPtr LoginToken { IntPtr get(); }
			/// <summary>
			/// Gets the impersonation token.
			/// </summary>
			/// <value>
			/// An <see cref="IntPtr"/> containing the user impersonation token, or IntPtr.Zero if not assigned.
			/// </value>
			property IntPtr ImpersonationToken {IntPtr get();}
			/// <summary>
			/// Gets the impersonation identity.
			/// </summary>
			/// <value>
			/// A <see cref="WindowsIdentity"/> instance representing the impersonation identity,
			/// or <b>null</b> if not assigned.
			/// </value>
			property WindowsIdentity^ ImpersonationIdentity { WindowsIdentity^ get();}
			/// <summary>
			/// Gets the impersonation context.
			/// </summary>
			/// <value>
			/// A <see cref="WindowsImpersonationContext"/> instance representing the impersonation context,
			/// or <b>null</b> if not assigned.
			/// </value>
			property WindowsImpersonationContext^ ImpersonationContext { WindowsImpersonationContext^ get();}
			/// <summary>
			/// Gets the name of the current user under whose credentials the thread is executing.
			/// </summary>
			/// <value>
			/// The name of the user who lanuched the process if not impersonating, or the name of the 
			/// user being impersonated.
			/// </value>
			property String^ CurrentUser { String^ get();}
	        #pragma endregion

			/*--------------------------------------------------------------------------------
			 * Public Methods / Functions
			 *------------------------------------------------------------------------------*/
			#pragma region Public Methods / Functions
			/// <summary>
			/// Terminates the current impersonation session, if active.
			/// </summary>
			void CloseSession();
			/// <summary>
			/// Initializes a new impersonation session.
			/// </summary>
			/// <param name="domain">The domain to log in to.</param>
			/// <param name="userName">The user name to log in as.</param>
			/// <param name="password">The password value to use.l</param>
			/// <returns>
			/// <b>true</b> if the impersonation is successful; otherwise, <b>false</b>.
			/// </returns>
			bool InitializeSession(String^ domain, String^ userName, String^ password);
	        #pragma endregion

		protected:
			/*--------------------------------------------------------------------------------
			 * Protected Event Methods / Functions
			 *------------------------------------------------------------------------------*/
			#pragma region Protected Event Methods / Functions
			/// <summary>
			/// Raises the <see cref="E:UserLoginSuccess"/> event.
			/// </summary>
			/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
			virtual void OnUserLoginSuccess(EventArgs^ e);
			/// <summary>
			/// Raises the <see cref="E:UserLoginFailure"/> event.
			/// </summary>
			/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
			virtual void OnUserLoginFailure(EventArgs^ e);
			/// <summary>
			/// Raises the <see cref="E:TokenDuplicationFailure"/> event.
			/// </summary>
			/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
			virtual void OnTokenDuplicationFailure(EventArgs^ e);
			/// <summary>
			/// Raises the <see cref="E:ImpersonationContextFailure"/> event.
			/// </summary>
			/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
			virtual void OnImpersonationContextFailure(EventArgs^ e);
			/// <summary>
			/// Raises the <see cref="E:ImpersionationSuccess"/> event.
			/// </summary>
			/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
			virtual void OnImpersionationSuccess(EventArgs^ e);
			/// <summary>
			/// Raises the <see cref="E:ImpersionationEnded"/> event.
			/// </summary>
			/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
			virtual void OnImpersionationEnded(EventArgs^ e);
			#pragma endregion
				
		private:

			/*--------------------------------------------------------------------------------
			 * Private Member Declarations
			 *------------------------------------------------------------------------------*/
			#pragma region Private Member Declarations
			/// <summary>
			/// Identity.
			/// </summary>
			WindowsIdentity^ _newIdentity;
			/// <summary>
			/// Context.
			/// </summary>
			WindowsImpersonationContext^ _impersonationContext;
			/// <summary>
			/// Login Token.
			/// </summary>
			IntPtr _originalLoginToken;
			/// <summary>
			/// Impersonation token.
			/// </summary>
			IntPtr _duplicatedToken;
			#pragma endregion

			/*--------------------------------------------------------------------------------
			 * Private Methods / Functions
			 *------------------------------------------------------------------------------*/
			#pragma region Private Methods / Functions
			/// <summary>
			/// Performs the user login.
			/// </summary>
			/// <param name="domain">The domain.</param>
			/// <param name="userName">Name of the user.</param>
			/// <param name="password">The password.</param>
			/// <returns>
			/// An <see cref="IntPtr"/> with the new token, or IntPtr.Zero on failure.
			/// </returns>
			IntPtr PerformUserLogin(String^ domain, String^ userName, String^ password);
			/// <summary>
			/// Logs a user onto the local machine.
			/// </summary>
			/// <param name="userName">Name of the user.</param>
			/// <param name="password">The password.</param>
			/// <returns>
			/// An <see cref="IntPtr"/> with the new token, or IntPtr.Zero on failure.
			/// </returns>
			IntPtr PerformUserLogin(String^ userName, String^ password);
			/// <summary>
			/// Performs the token duplication.
			/// </summary>
			/// <returns>
			/// An <see cref="IntPtr"/> with the new token, or IntPtr.Zero on failure.
			/// </returns>
			IntPtr PerformTokenDuplication();
			/// <summary>
			/// Creates the identity.
			/// </summary>
			/// <returns>
			/// <b>true</b> if the operation is successful; otherwise, <b>false</b>.
			/// </returns>
			bool CreateIdentity();
			/// <summary>
			/// Creates the impersonation context.
			/// </summary>
			/// <returns>
			/// <b>true</b> if the operation is successful; otherwise, <b>false</b>.
			/// </returns>
			bool CreateContext();
			#pragma endregion

			/*--------------------------------------------------------------------------------
			 * Private "Safe" API Function Wrappers
			 *------------------------------------------------------------------------------*/
			#pragma region Private "Safe" API Function Wrappers
			/// <summary>
			/// Logs the user into the system.
			/// </summary>
			/// <param name="userId">The ID of the user.</param>
			/// <param name="domain">The domain to log into.</param>
			/// <param name="password">The password of the user account.</param>
			/// <param name="logonType">The type of login to perform.</param>
			/// <param name="logonProvider">The network authentication provider.</param>
			/// <returns>
			/// An <see cref="IntPtr"/> that contains the user token if successful; otherwise,
			/// returns <see cref="IntPtr.Zero"/>.
			/// </returns>
			IntPtr SafeLogonUser(String^ userId, String^ domain, String^ password,
												int logonType, int logonProvider);
			/// <summary>
			/// Closes an open handle value.
			/// </summary>
			/// <param name="handleValue">
			/// An <see cref="IntPtr"/> containing the handle to be closed.
			/// </param>
			/// <returns>
			/// <b>true</b> if the operation is successful; otherwise, returns <b>false</b>.
			/// </returns>
			bool CloseOpenHandle(IntPtr handleValue);
			/// <summary>
			/// Duplicates a user token.
			/// </summary>
			/// <param name="originalToken">The existing handle to duplication.</param>
			/// <param name="impersonationLevel">The impersonation level.</param>
			/// <returns>
			/// An <see cref="IntPtr"/> containing the new token if successful; otherwise,
			/// returns <see cref="IntPtr.Zero"/>.
			/// </returns>
			IntPtr DuplicateUserToken(IntPtr originalToken, int impersonationLevel);
			#pragma endregion
		};
	}
}